#include <iostream>
#include <GLFW/glfw3.h>

#include "events.hpp"
#include "cursor.hpp"
#include "window.hpp"

bool* carbon::C_Events::_keys;
uint32_t* carbon::C_Events::_frames;
uint32_t carbon::C_Events::_currentFrame;

#define _MOUSE_BUTTONS 1024

int carbon::C_Events::initialize() {
    GLFWwindow* win = carbon::C_Window::_window;

    _keys = new bool[1032]{0};
    _frames = new uint32_t[1032]{0};

    glfwSetKeyCallback(win, carbon::C_Events::glfwKeyCallback);
    glfwSetMouseButtonCallback(win, carbon::C_Events::glfwMouseButtonCallback);
    glfwSetCursorPosCallback(win, carbon::C_Events::glfwCursorPosCallback);
    glfwSetFramebufferSizeCallback(win, carbon::C_Events::glfwFramebufferSizeCallback);

    return 0;
}

// glfw key callback implementation for Carbon
void carbon::C_Events::glfwKeyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) {
	if (action == GLFW_PRESS) {        // if pressed..
		_keys[key] = true;             // set pressed key index to true..
		_frames[key] = _currentFrame;  // and update frames index.
	}
	else if (action == GLFW_RELEASE) { // if released..
		_keys[key] = false;            // set released key index to false..
		_frames[key] = _currentFrame;  // and update frames index.
	}
}

// glfw mouse button callback implementation for Carbon
void carbon::C_Events::glfwMouseButtonCallback(GLFWwindow* win, int button, int action, int mode) {
	if (action == GLFW_PRESS) {
		_keys[_MOUSE_BUTTONS+button] = true;
		_frames[_MOUSE_BUTTONS+button] = _currentFrame;
	}
	else if (action == GLFW_RELEASE) {
		_keys[_MOUSE_BUTTONS+button] = false;
		_frames[_MOUSE_BUTTONS+button] = _currentFrame;
	}
}

// glfw cursor position callback implementation for Carbon Engine
void carbon::C_Events::glfwCursorPosCallback(GLFWwindow* win, double xpos, double ypos) {
    if (carbon::C_Cursor::started) {                               // if cursor has started..
        carbon::C_Cursor::deltaX += ypos - carbon::C_Cursor::xpos; // ..update delta position x..
        carbon::C_Cursor::deltaY += xpos - carbon::C_Cursor::ypos; // ..update delta position y.
    } else { 
        carbon::C_Cursor::started = true;  // otherwise say that cursor has started
    }

    // update positions
    carbon::C_Cursor::xpos = xpos; 
    carbon::C_Cursor::ypos = ypos;
}

// glfw framebuffer size change callback implementation for Carbon Engine
void carbon::C_Events::glfwFramebufferSizeCallback(GLFWwindow* win, int w, int h) {
    glViewport(0, 0, w, h);
}

bool carbon::C_Events::pressed(int keycode) {
    if (keycode < 0 || keycode >= _MOUSE_BUTTONS) {
        return false;
    }
    return _keys[keycode];
}

bool carbon::C_Events::justPressed(int keycode) {
    if (keycode < 0 || keycode >= _MOUSE_BUTTONS) {
        return false;
    }
    return _keys[keycode] && _frames[keycode] == _currentFrame;
}

bool carbon::C_Events::clicked(int button) {
    return _keys[_MOUSE_BUTTONS + button];
}

bool carbon::C_Events::justClicked(int button) {
    return _keys[_MOUSE_BUTTONS + button] && _frames[_MOUSE_BUTTONS + button] == _currentFrame;
}

void carbon::C_Events::poll() {
    _currentFrame++;

    carbon::C_Cursor::deltaX = 0.0f;
    carbon::C_Cursor::deltaY = 0.0f;

    glfwPollEvents(); 
}
